#pragma once
#include <vector>
#include "Mutex.h"

class MessageQueue
{
    typedef std::vector< char > BufferContainer;
    typedef DWORD  LengthType;
    typedef std::vector< LengthType >   LengthList;

public:
    MessageQueue();
    ~MessageQueue();

    void Push( const char *data, const DWORD &size );
    const char* Data() const;
    DWORD DataSize() const;

    void Switch();

    bool Empty() const;
    void Next();

private:
    MessageQueue( const MessageQueue& );
    MessageQueue& operator =( const MessageQueue& );

private:
    BufferContainer m_buffer;
    BufferContainer m_switch_buffer;
    LengthList      m_len_list;
    LengthList      m_switch_len_list;
    Mutex           m_mutex;
    const char      *m_data;
    DWORD			m_pos;
};

// inline methords of MessageQueue
inline MessageQueue::MessageQueue()
    : m_data( NULL )
    , m_pos( 0 )
{
}

inline MessageQueue::~MessageQueue()
{
}

inline void MessageQueue::Push( const char *data, const DWORD &size )
{
    ScopedLock lock( m_mutex );
    DWORD pos = m_switch_buffer.size();
    m_switch_buffer.resize( size + pos );
    memcpy( &m_switch_buffer[pos], data, size );
    m_switch_len_list.push_back( size );
}

inline const char* MessageQueue::Data() const
{
    return m_data;
}

inline DWORD MessageQueue::DataSize() const
{
    return m_len_list[m_pos];
}

inline void MessageQueue::Switch()
{
    ScopedLock lock( m_mutex );

    if( !m_switch_len_list.empty() )
    {
        m_buffer.resize( m_switch_buffer.size() );
        memcpy( &m_buffer[0], &m_switch_buffer[0], m_buffer.size() );
        m_len_list.resize( m_switch_len_list.size() );
        memcpy( &m_len_list[0], &m_switch_len_list[0], sizeof( LengthType ) * m_len_list.size() );

        m_switch_len_list.clear();
        m_switch_buffer.clear();

        m_data = &m_buffer[0];
    }
}

inline bool MessageQueue::Empty() const
{
    return m_len_list.empty() || m_len_list.size() <= m_pos;
}

inline void MessageQueue::Next()
{
    m_data += m_len_list[m_pos];
    ++m_pos;

    if( m_len_list.size() == m_pos )
    {
        m_buffer.clear();
        m_len_list.clear();
        m_pos = 0;
        m_data = 0;
    }
}

